package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.TsCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;
    @Autowired
    private AlbumStatMapper albumStatMapper;
    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 保存专辑信息
     *
     * @param albumInfoVo 专辑信息的Vo对象，包含专辑的基本信息以及专辑属性值列表
     * @param userId 用户ID，用于关联相册和用户
     *
     * 此方法使用了事务注解，确保在出现异常时回滚事务
     */
    /*
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo,Long userId) {
        // 创建相册信息对象，并从Vo对象中复制属性
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo,albumInfo);
        // 设置相册状态为已通过
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
        // 设置相册所属用户ID
        albumInfo.setUserId(userId);
        // 如果相册不是免费类型，则设置默认的免费试听曲目数量
        if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())){
            albumInfo.setTracksForFree(5);
        }
        // 插入相册信息到数据库
        albumInfoMapper.insert(albumInfo);

        // 处理相册属性值列表
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)){
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                // 创建相册属性值对象，并从Vo对象中复制属性
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                BeanUtils.copyProperties(albumAttributeValueVo,albumAttributeValue);
                // 设置相册ID
                albumAttributeValue.setAlbumId(albumInfo.getId());
                // 插入相册属性值到数据库
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }

        // 保存相册统计信息，初始化播放、订阅、浏览和评论的统计
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_PLAY);
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_SUBSCRIBE);
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_BROWSE);
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_COMMENT);
        if ("1".equals(albumInfo.getIsOpen())){
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumInfo.getId());
        }
    }*/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo,albumInfo);
        albumInfo.setUserId(userId);
        albumInfo.setStatus(SystemConstant.PAYMENT_STATUS_PAID);
        if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())){
            albumInfo.setTracksForFree(5);
        }
        albumInfoMapper.insert(albumInfo);
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)){
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                BeanUtils.copyProperties(albumAttributeValueVo,albumAttributeValue);
                albumAttributeValue.setAlbumId(albumInfo.getId());
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_PLAY);
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_SUBSCRIBE);
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_BROWSE);
        this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_COMMENT);

        if ("1".equals(albumInfo.getIsOpen())){
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumInfo.getId());
            //获取布隆过滤器
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            //把专辑id添加到过滤器中
            bloomFilter.add(albumInfo.getId());
        }
    }

    /**
     * 保存相册统计数据
     *
     * @param id 相册ID，用于标识特定的相册
     * @param type 统计类型，描述统计数据的种类（如点赞、浏览等）
     *
     * 此方法负责创建并保存相册统计数据对象它首先实例化一个AlbumStat对象，
     * 然后设置相册ID、统计类型和统计数值统计数值是随机生成的，范围在0到10000之间
     * 最后，使用albumStatMapper将统计数据对象插入到数据库中
     */
    private void saveAlbumStat(Long id, String type) {
        // 实例化专辑统计数据对象
        AlbumStat albumStat = new AlbumStat();
        // 设置专辑ID
        albumStat.setAlbumId(id);
        // 设置统计类型
        albumStat.setStatType(type);
        // 随机生成统计数值
        albumStat.setStatNum(new Random().nextInt(10000));
        // 将统计数据对象插入数据库
        albumStatMapper.insert(albumStat);
    }

    /**
     * 查询专辑分页列表
     * @param albumInfoPage
     * @param albumInfoQuery
     * @return
     */
    @Override
    public IPage<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> albumInfoPage, AlbumInfoQuery albumInfoQuery) {
        return albumInfoMapper.selectUserAlbumPage(albumInfoPage,albumInfoQuery);
    }

    /**
     * 根据ID删除专辑信息
     * 此方法首先检查专辑下是否存在未删除的声音（音轨），如果存在，则抛出异常
     * 如果专辑下没有声音，则继续删除专辑信息及其相关属性和统计信息
     *
     * @param id 专辑的唯一标识符
     * @throws GuiguException 如果专辑下存在未删除的声音时抛出此异常
     */
    /*
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeAlbumInfoById(Long id) {
        // 创建查询条件，检查专辑下是否存在未删除的声音
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        Long count = trackInfoMapper.selectCount(queryWrapper.eq(TrackInfo::getAlbumId, id));
        // 如果专辑下存在未删除的声音，抛出异常
        if (count>0){
            throw new GuiguException(400,"该专辑下存在未删除的声音");
        }
        // 删除专辑信息
        albumInfoMapper.deleteById(id);
        // 删除与专辑相关的属性值
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,id));
        // 删除与专辑相关的统计信息
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId,id));
    }*/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeAlbumInfoById(Long id) {
        Long count = trackInfoMapper.selectCount(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, id));
        if (count>0){
            throw new GuiguException(400,"该专辑下有未删除的声音");
        }
        albumInfoMapper.deleteById(id);
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,id));
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId,id));
        rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_LOWER,id);
    }

    /**
     * 根据专辑ID获取专辑信息
     *
     * @param id 专辑的唯一标识符
     * @return 返回一个包含专辑信息的AlbumInfoVo对象，包括专辑的基本信息和属性值
     */
    @TsCache(prefix = "album:")
    @Override
    public AlbumInfo getAlbumInfoById(Long id) {
        //	根据id 查询专辑数据
        AlbumInfo albumInfo = this.getById(id);
        //	回显时，需要回显专辑数据信息数据
        if (albumInfo!=null){
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, id));
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValueList);
        }
        return albumInfo;
    }

    /**
     * 更新专辑信息
     *
     * @param id 专辑ID，用于标识要更新的专辑
     * @param albumInfoVo 包含相册更新信息的视图对象，用于更新专辑信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo) {
        // 根据ID查询相册信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(id);
        // 将视图对象中的属性复制到相册信息对象中，准备更新数据库
        BeanUtils.copyProperties(albumInfoVo,albumInfo);
        // 更新相册信息到数据库
        albumInfoMapper.updateById(albumInfo);
        // 删除相册原有的所有属性值，以便重新插入更新后的属性值
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,id));
        // 获取相册属性值视图对象列表
        List<AlbumAttributeValueVo> attributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        // 如果属性值列表不为空，则遍历每个属性值视图对象
        if (!CollectionUtils.isEmpty(attributeValueVoList)){
            for (AlbumAttributeValueVo albumAttributeValueVo : attributeValueVoList) {
                // 创建新的相册属性值对象
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                // 将属性值视图对象中的属性复制到相册属性值对象中
                BeanUtils.copyProperties(albumAttributeValueVo,albumAttributeValue);
                // 设置相册ID
                albumAttributeValue.setAlbumId(id);
                // 插入新的相册属性值到数据库
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }
        if ("1".equals(albumInfo.getIsOpen())){
            //上架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumInfo.getId());
            //获取布隆过滤器
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            //把专辑id添加到过滤器中
            bloomFilter.add(id);
        }else {
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_LOWER,albumInfo.getId());
        }
    }

    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        Page<AlbumInfo> page = new Page<>();
        LambdaQueryWrapper<AlbumInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AlbumInfo::getUserId,userId).select(AlbumInfo::getId,AlbumInfo::getAlbumTitle).orderByDesc(AlbumInfo::getId);
        return albumInfoMapper.selectPage(page,queryWrapper).getRecords();
    }

    @TsCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
    @Override
    public AlbumStatVo getAlbumStat(Long id) {
        return albumStatMapper.selectAlbumStat(id);
    }

}
